"""
This is the CGI server to provision Aladino VoIP devices.
"""

import cgi, os, sys

from pivelli.cgi import strings as xml_strings
from pivelli.cgi.options import status_dir, get_clis

class CGIException(Exception):
	pass
	
class UnavailableCLIException(Exception):
	pass
	
class AlreadyRegisteredCLIException(Exception):
	pass

def status_filename(cli):
	"""
	Returns the filename for the status of a given CLI.
	"""
	return os.path.join(status_dir, cli + ".status")

def status_file(cli, mode="r"):
	"""
	Returns the handler for a status file.
	"""
	try:
		return open(status_filename(cli), mode)
	except IOError:
		return None

def status(cli):
	"""
	Look for a file in the status directory and check whether the CLI
	is marked as registered or not. Returns the IP of the registrant, or
	None if it is not registered.
	"""
	s = status_file(cli)
	if not s:
		return None
	else:
		return s.read()

def status_all():
	"""
	Returns the status of all local CLIs listed in the configuration file.
	"""
	status_dict = {}
	for cli in local_clis:
		status_dict[cli] = status(cli)
	return status_dict

def register(cli, ip):
	"""
	Mark the given CLI as registered to the given IP address.
	"""
	if cli not in local_clis:
		raise UnavailableCLIException, '%s not in configured local CLIs' % cli
	current_status = status(cli)
	if current_status and not current_status == ip:
		raise AlreadyRegisteredCLIException, '%s registered to %s' % (cli, current_status)
	status_file(cli, 'w').write(ip)

def delete(ip, skip=[]):
	"""
	Check all status files and delete all those belonging to the given IP.
	If the optional ``skip`` parameter is provided, then do not delete
	the CLIs in that list.
	
	This is because 'setcli' sets ONLY the provided CLIs, and unregisters any
	others assigned to that IP.
	"""
	for cli in local_clis:
		if cli not in skip and status(cli) == ip:
			os.remove(status_filename(cli))

def cgi_output(string):
	"""
	Outputs the response AND EXITS.
	"""
	print 'Content-type: text/xml'
	print 'Cache-Control: no-cache'
	print 'Connection: close'
	print
	print string
	sys.exit(0)

form = cgi.FieldStorage()
action = form.getfirst('WINDWEB_URL')
source_ip = os.environ['REMOTE_ADDR']
local_clis = get_clis(source_ip)

if action == '/doc2/askcli':
	status_lines = []
	for cli, ip in status_all().items():
		if ip:
			status = 'Registered'
		else:
			status = 'Available'
		status_lines.append(xml_strings.cli_entry % {'cli': cli, 'status': status})
	cgi_output(xml_strings.askcli % {'cli_list': ''.join(status_lines)})
	
elif action == '/doc2/setcli':
	# Get all CLI parameters
	clis = []
	for cli_parameter in ('CLI', 'CLI2', 'CLI3', 'CLI4', 'CLI5'):
		cli = form.getfirst(cli_parameter)
		if cli:
			clis.append(cli)
			
	# Register
	error_codes_dict = {}
	parameters_dict = {}
	for cli in clis:
		try:
			register(cli, source_ip)
			error_codes_dict[cli] = '0'
			parameters_dict[cli] = {'cli': cli, 'domain': '',
		'key': '', 'outbound_proxy': ''}
		except UnavailableCLIException:
			error_codes_dict[cli] = '2'
		except AlreadyRegisteredCLIException:
			error_codes_dict[cli] = '3'
	
	# Prepare output
	error_codes = []
	for cli, code in error_codes_dict.items():
		error_codes.append(xml_strings.cli_errorcode_entry % {'cli': cli, 'error_code': code})
	
	parameters = []
	for line in parameters_dict.values():
		parameters.append(xml_strings.cli_parameters_entry % line)
	
	# Delete any previous leftover registrations
	delete(source_ip, skip=clis)
	
	# Output results
	cgi_output(xml_strings.setcli % { 'error_codes': ''.join(error_codes),
		'parameters': ''.join(parameters)})
		
elif action == '/doc2/delallcli':
	delete(source_ip)
	cgi_output(xml_strings.delallcli)
	
else:
	raise 'Unrecognized action'
